﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Text;
using FatHibernation.Data;
using FatHibernation.DataInterface;
using NHibernate;
using NHibernate.Cfg;
using NHibernate.Tool.hbm2ddl;

namespace FatHibernation.DataSession
{
    public class DataSessionHandler : IDataSessionHandler
    {
        private ISessionFactory _factory;

        private Configuration GetConfiguration()
        {
            Configuration configuration = new Configuration();

            bool useMSSQL = (ConfigurationSettings.AppSettings["DatabaseType"] == "mssql");
            if (useMSSQL)
            {
                configuration.SetProperty(NHibernate.Cfg.Environment.Dialect, DataConfigurationSettings.Dialect_MSSQL);
                configuration.SetProperty(NHibernate.Cfg.Environment.ConnectionProvider, DataConfigurationSettings.Provider_MSSQL);
                configuration.SetProperty(NHibernate.Cfg.Environment.ConnectionDriver, DataConfigurationSettings.Driver_MSSQL);
            }
            else
            {
                configuration.SetProperty(NHibernate.Cfg.Environment.Dialect, DataConfigurationSettings.Dialect_mySQL);
                configuration.SetProperty(NHibernate.Cfg.Environment.ConnectionProvider, DataConfigurationSettings.Provider_mySQL);
                configuration.SetProperty(NHibernate.Cfg.Environment.ConnectionDriver, DataConfigurationSettings.Driver_mySQL);
            }

            configuration.SetProperty(NHibernate.Cfg.Environment.ConnectionString, System.Configuration.ConfigurationSettings.AppSettings["SQLConnectionString"]);
            configuration.SetProperty(NHibernate.Cfg.Environment.UseProxyValidator, "true");


            /*
            _cfg.SetProperty(NHibernate.Cfg.Environment.UseSecondLevelCache, "true");
            _cfg.SetProperty(NHibernate.Cfg.Environment.CacheProvider, "NHibernate.Caches.MemCache.MemCacheProvider,NHibernate.Caches.MemCache");
            _cfg.SetProperty("relativeExpiration", "1200");
             */

            // load all the embedded hbm.xml mapping files in the assembly
            configuration.AddAssembly(ConfigurationSettings.AppSettings["BusinessAssembly"]);
            return configuration;
        }

        private ISessionFactory GetFactory()
        {
            if (_factory == null)
                _factory = GetConfiguration().BuildSessionFactory();
            return _factory;
        }

        public void OpenSession()
        {
            DataContextStorage.Session = GetFactory().OpenSession();
        }

        public void CloseSession()
        {
            if (DataContextStorage.Session != null && DataContextStorage.Session.IsOpen)
            {
                DataContextStorage.Session.Close();
            }
            DataContextStorage.ClearSession();
        }

        public bool IsSessionOpen
        {
            get { return DataContextStorage.Session != null; }
        }




        public void BeginWriteTransaction()
        {
            BeginTransaction(IsolationLevel.RepeatableRead, FlushMode.Auto);
        }

        public void BeginReadTransaction()
        {
            BeginTransaction(IsolationLevel.ReadCommitted, FlushMode.Never);
        }
        
        private void BeginTransaction(IsolationLevel isolationLevel, FlushMode flushMode)
        {
            if (!IsSessionOpen)
                throw new InvalidOperationException("Can't begin transaction with no open session!");
            
            ITransaction tx = DataContextStorage.Session.BeginTransaction(isolationLevel);
            DataContextStorage.CurrentTransaction = tx;
            DataContextStorage.Session.FlushMode = flushMode;
        }


        public void CommitCurrentTransaction()
        {
            DataContextStorage.CurrentTransaction.Commit();
            DataContextStorage.ClearTransaction();
        }

        public bool IsTransactionActive
        {
            get { return DataContextStorage.CurrentTransaction != null &&
                         DataContextStorage.CurrentTransaction.IsActive; }
        }

        public void RollbackCurrentTransaction()
        {
            if (IsTransactionActive)
                DataContextStorage.CurrentTransaction.Rollback();
        }




        public void CreateDatabase()
        {
            SchemaExport schemaExport = new SchemaExport(GetConfiguration());
            schemaExport.Create(false, true);
        }
    }
}
